package internal

import (
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

// Duration 自定义时间类型用于JSON解析
type Duration time.Duration

// UnmarshalJSON 自定义JSON解析
func (d *Duration) UnmarshalJSON(data []byte) error {
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	
	duration, err := time.ParseDuration(s)
	if err != nil {
		return err
	}
	
	*d = Duration(duration)
	return nil
}

// MarshalJSON 自定义JSON序列化
func (d Duration) MarshalJSON() ([]byte, error) {
	return json.Marshal(time.Duration(d).String())
}

// String 转换为字符串
func (d Duration) String() string {
	return time.Duration(d).String()
}

// ToDuration 转换为time.Duration
func (d Duration) ToDuration() time.Duration {
	return time.Duration(d)
}

// TableSyncCondition 表条件同步配置
type TableSyncCondition struct {
	// WhereCondition WHERE条件，用于筛选要同步的数据
	WhereCondition string `json:"where_condition"`
	
	// SyncFields 指定要同步的字段，为空则同步所有字段
	SyncFields []string `json:"sync_fields"`
	
	// KeyFields 主键字段，用于数据匹配和更新
	KeyFields []string `json:"key_fields"`
	
	// SyncMode 同步模式：insert_only, update_only, upsert(默认)
	SyncMode string `json:"sync_mode"`
	
	// BatchSize 批量同步的大小，默认1000
	BatchSize int `json:"batch_size"`
	
	// DeleteCondition 删除条件，满足此条件的目标数据将被删除
	DeleteCondition string `json:"delete_condition"`
}

// Config config struct
type Config struct {
	// SourceDSN 同步的源头
	SourceDSN string `json:"source" validate:"required"`
	SourceSSH string `json:"source_ssh"`

	// DestDSN 将被同步
	DestDSN string `json:"dest" validate:"required"`
	DestSSH string `json:"dest_ssh"`

	ConfigPath string `json:"-"`

	// 要同步的数据库
	Schemas []string `json:"schemas" validate:"required,min=1"`

	// Tables 同步表的白名单，若为空，则同步全库
	Tables []string `json:"tables"`

	// TablesIgnore 不同步的表
	TablesIgnore []string `json:"tables_ignore"`

	// TablesCompareData 要进行数据比较的表
	TablesCompareData []string `json:"tables_compare_data"`

	// TablesSyncConditions 表字段条件同步配置
	TablesSyncConditions map[string]TableSyncCondition `json:"tables_sync_conditions"`

	// Sync 是否真正的执行同步操作
	Sync bool `json:"-"`

	// Drop 若目标数据库表比源头多了字段、索引，是否删除
	Drop bool `json:"-"`

	// SingleSchemaChange 生成sql ddl语言每条命令只会进行单个修改操作
	SingleSchemaChange bool `json:"single_schema_change"`

	// 连接超时时间
	ConnectTimeout Duration `json:"connect_timeout"`
	
	// 查询超时时间
	QueryTimeout Duration `json:"query_timeout"`
	
	// 最大重试次数
	MaxRetries int `json:"max_retries"`
	
	// 日志级别
	LogLevel string `json:"log_level"`
	
	// 日志文件路径
	LogFile string `json:"log_file"`
}

// DefaultConfig 返回默认配置
func DefaultConfig() *Config {
	return &Config{
		ConnectTimeout: Duration(30 * time.Second),
		QueryTimeout:   Duration(300 * time.Second),
		MaxRetries:     3,
		LogLevel:       "info",
		Tables:         []string{},
		TablesIgnore:   []string{},
		TablesCompareData: []string{},
		TablesSyncConditions: make(map[string]TableSyncCondition),
	}
}

func (cfg *Config) String() string {
	// 隐藏敏感信息
	safeCfg := *cfg
	if safeCfg.SourceDSN != "" {
		safeCfg.SourceDSN = maskDSN(safeCfg.SourceDSN)
	}
	if safeCfg.DestDSN != "" {
		safeCfg.DestDSN = maskDSN(safeCfg.DestDSN)
	}
	if safeCfg.SourceSSH != "" {
		safeCfg.SourceSSH = maskSSH(safeCfg.SourceSSH)
	}
	if safeCfg.DestSSH != "" {
		safeCfg.DestSSH = maskSSH(safeCfg.DestSSH)
	}
	
	ds, _ := json.MarshalIndent(safeCfg, "  ", "  ")
	return string(ds)
}

// maskDSN 遮蔽DSN中的密码
func maskDSN(dsn string) string {
	// user:password@host:port -> user:***@host:port
	if strings.Contains(dsn, "@") {
		parts := strings.Split(dsn, "@")
		if len(parts) == 2 {
			userInfo := strings.Split(parts[0], ":")
			if len(userInfo) >= 2 {
				return userInfo[0] + ":***@" + parts[1]
			}
		}
	}
	return dsn
}

// maskSSH 遮蔽SSH中的密码
func maskSSH(ssh string) string {
	// user:password@host:port -> user:***@host:port
	if strings.Contains(ssh, ":") && strings.Contains(ssh, "@") {
		parts := strings.Split(ssh, "@")
		if len(parts) == 2 {
			userInfo := strings.Split(parts[0], ":")
			if len(userInfo) >= 2 {
				return userInfo[0] + ":***@" + parts[1]
			}
		}
	}
	return ssh
}

// CheckMatchTables check table is match
func (cfg *Config) CheckMatchTables(name string) bool {
	// 若没有指定表，则意味对全库进行同步
	if len(cfg.Tables) == 0 {
		return true
	}
	for _, tableName := range cfg.Tables {
		if simpleMatch(tableName, name, "CheckMatchTables") {
			return true
		}
	}
	return false
}

func (cfg *Config) SetTables(tables []string) {
	for _, name := range tables {
		name = strings.TrimSpace(name)
		if len(name) > 0 {
			cfg.Tables = append(cfg.Tables, name)
		}
	}
}

// SetTablesIgnore 设置忽略
func (cfg *Config) SetTablesIgnore(tables []string) {
	for _, name := range tables {
		name = strings.TrimSpace(name)
		if len(name) > 0 {
			cfg.TablesIgnore = append(cfg.TablesIgnore, name)
		}
	}
}

// set tables to compare data，* is supported
func (cfg *Config) SetTablesCompareData(tables []string) {
	for _, name := range tables {
		name = strings.TrimSpace(name)
		if len(name) > 0 {
			cfg.TablesCompareData = append(cfg.TablesCompareData, name)
		}
	}
}

// CheckMatchCompareDataTables check TablesCompareData is match
func (cfg *Config) CheckMatchCompareDataTables(name string) bool {
	if len(cfg.TablesCompareData) == 0 {
		return false
	}
	for _, tableName := range cfg.TablesCompareData {
		if simpleMatch(tableName, name, "CheckMatchCompareDataTables") {
			return true
		}
	}
	return false
}

// CheckMatchIgnoreTables check table_Ignore is match
func (cfg *Config) CheckMatchIgnoreTables(name string) bool {
	if len(cfg.TablesIgnore) == 0 {
		return false
	}
	for _, tableName := range cfg.TablesIgnore {
		if simpleMatch(tableName, name, "CheckMatchTables") {
			return true
		}
	}
	return false
}

// Validate validates the configuration
func (cfg *Config) Validate() error {
	if err := ValidateNotEmpty(cfg.SourceDSN, "source DSN"); err != nil {
		return err
	}
	if err := ValidateNotEmpty(cfg.DestDSN, "dest DSN"); err != nil {
		return err
	}
	if len(cfg.Schemas) == 0 {
		return NewValidationError("schemas cannot be empty", nil)
	}
	
	// 验证DSN格式
	if err := cfg.validateDSN(cfg.SourceDSN, "source DSN"); err != nil {
		return err
	}
	if err := cfg.validateDSN(cfg.DestDSN, "dest DSN"); err != nil {
		return err
	}
	
	// 验证超时时间
	if cfg.ConnectTimeout <= 0 {
		cfg.ConnectTimeout = Duration(30 * time.Second)
	}
	if cfg.QueryTimeout <= 0 {
		cfg.QueryTimeout = Duration(300 * time.Second)
	}
	if cfg.MaxRetries < 0 {
		cfg.MaxRetries = 3
	}
	
	// 验证条件同步配置
	if cfg.TablesSyncConditions == nil {
		cfg.TablesSyncConditions = make(map[string]TableSyncCondition)
	}
	
	for tableName, condition := range cfg.TablesSyncConditions {
		if err := cfg.ValidateTableSyncCondition(tableName, condition); err != nil {
			return NewValidationError(fmt.Sprintf("invalid sync condition for table %s", tableName), err)
		}
	}
	
	return nil
}

// validateDSN 验证DSN格式
func (cfg *Config) validateDSN(dsn, name string) error {
	// 基本格式检查: user:password@host:port
	if !strings.Contains(dsn, "@") {
		return NewValidationError(fmt.Sprintf("%s format invalid, missing @", name), nil)
	}
	
	parts := strings.Split(dsn, "@")
	if len(parts) != 2 {
		return NewValidationError(fmt.Sprintf("%s format invalid", name), nil)
	}
	
	userInfo := parts[0]
	hostInfo := parts[1]
	
	if userInfo == "" || hostInfo == "" {
		return NewValidationError(fmt.Sprintf("%s format invalid, missing user info or host info", name), nil)
	}
	
	if !strings.Contains(userInfo, ":") {
		return NewValidationError(fmt.Sprintf("%s format invalid, missing password", name), nil)
	}
	
	return nil
}

// Check check config (deprecated, use Validate instead)
func (cfg *Config) Check() {
	if err := cfg.Validate(); err != nil {
		Fatal("Config validation failed: %v", err)
	}
}

// LoadConfig load config file
func LoadConfig(confPath string) (*Config, error) {
	Info("Loading configuration from %s", confPath)
	
	// 先加载默认配置
	cfg := DefaultConfig()
	
	// 加载配置文件
	if err := loadJSONFile(confPath, cfg); err != nil {
		return nil, NewConfigError(fmt.Sprintf("failed to load config file %s", confPath), err)
	}
	
	cfg.ConfigPath = confPath
	
	// 验证配置
	if err := cfg.Validate(); err != nil {
		return nil, NewConfigError("configuration validation failed", err)
	}
	
	// 设置日志级别
	if err := cfg.setupLogging(); err != nil {
		return nil, NewConfigError("failed to setup logging", err)
	}
	
	Info("Configuration loaded successfully")
	Debug("Configuration: %s", cfg.String())
	
	return cfg, nil
}

// setupLogging 设置日志
func (cfg *Config) setupLogging() error {
	// 设置日志级别
	switch strings.ToLower(cfg.LogLevel) {
	case "debug":
		SetLogLevel(LogLevelDebug)
	case "info":
		SetLogLevel(LogLevelInfo)
	case "warn":
		SetLogLevel(LogLevelWarn)
	case "error":
		SetLogLevel(LogLevelError)
	default:
		SetLogLevel(LogLevelInfo)
	}
	
	// 设置日志文件
	if cfg.LogFile != "" {
		if err := SetupLogFile(cfg.LogFile); err != nil {
			return err
		}
	}
	
	return nil
}

// GetTableSyncCondition 获取表的条件同步配置
func (cfg *Config) GetTableSyncCondition(tableName string) (TableSyncCondition, bool) {
	condition, exists := cfg.TablesSyncConditions[tableName]
	if !exists {
		return TableSyncCondition{}, false
	}
	
	// 设置默认值
	if condition.SyncMode == "" {
		condition.SyncMode = "upsert"
	}
	if condition.BatchSize <= 0 {
		condition.BatchSize = 1000
	}
	
	return condition, true
}

// SetTableSyncCondition 设置表的条件同步配置
func (cfg *Config) SetTableSyncCondition(tableName string, condition TableSyncCondition) {
	if cfg.TablesSyncConditions == nil {
		cfg.TablesSyncConditions = make(map[string]TableSyncCondition)
	}
	cfg.TablesSyncConditions[tableName] = condition
}

// CheckHasConditionalSync 检查是否有条件同步配置
func (cfg *Config) CheckHasConditionalSync() bool {
	return len(cfg.TablesSyncConditions) > 0
}

// ValidateTableSyncCondition 验证表条件同步配置
func (cfg *Config) ValidateTableSyncCondition(tableName string, condition TableSyncCondition) error {
	if condition.WhereCondition == "" {
		return NewConfigError("where_condition is required for conditional sync", nil)
	}
	
	if len(condition.KeyFields) == 0 {
		return NewConfigError("key_fields is required for conditional sync", nil)
	}
	
	validSyncModes := []string{"insert_only", "update_only", "upsert"}
	if condition.SyncMode != "" {
		found := false
		for _, mode := range validSyncModes {
			if condition.SyncMode == mode {
				found = true
				break
			}
		}
		if !found {
			return NewConfigError(fmt.Sprintf("invalid sync_mode: %s, valid values are: %s", 
				condition.SyncMode, strings.Join(validSyncModes, ", ")), nil)
		}
	}
	
	if condition.BatchSize < 0 {
		return NewConfigError("batch_size must be positive", nil)
	}
	
	return nil
}
